package com.restkeeper.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
import com.aliyuncs.profile.DefaultProfile;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Strings;
import com.restkeeper.config.AliyunSmsConfig;
import com.restkeeper.config.WXConfig;
import com.restkeeper.config.WeChatConfig;
import com.restkeeper.constants.SmsTemplateIdEum;
import com.restkeeper.dto.WechatRefundDto;
import com.restkeeper.dto.WxPayDto;
import com.restkeeper.entity.*;
import com.restkeeper.mapper.*;
import com.restkeeper.model.WxPrepayResp;
import com.restkeeper.model.aliyun.SmsMessageDto;
import com.restkeeper.model.WeChatMessage;
import com.restkeeper.utils.http.HttpUtils;
import com.restkeeper.utils.wx.WechatMessageUtils;
import com.restkeeper.vo.UserInfoResponse;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.core.notification.NotificationConfig;
import com.wechat.pay.java.service.partnerpayments.jsapi.model.Transaction;
import com.wechat.pay.java.service.payments.jsapi.JsapiServiceExtension;
import com.wechat.pay.java.service.payments.jsapi.model.*;
import com.wechat.pay.java.service.refund.RefundService;
import com.wechat.pay.java.service.refund.model.AmountReq;
import com.wechat.pay.java.service.refund.model.CreateRequest;
import com.wechat.pay.java.service.refund.model.Refund;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import java.math.BigDecimal;
import java.util.*;

@Service
@RefreshScope
@Slf4j
@RequiredArgsConstructor
public class CommonServiceImpl implements CommonService{
    private final SystemConfigMapper systemConfigMapper;
    private final WeChatConfig weChatConfig;
    private final AliyunSmsConfig aliyunSmsConfig;
    private final WXConfig wxConfig;

    @Value("${douyin.appId}")
    private String douyinAppId;

    @Value("${douyin.secret}")
    private String douyinAppSecret;
    private static final ObjectMapper objectMapper = new ObjectMapper();

    @Override
    public JSONObject getACCESSInfo(String jsCode) {
        //参数校验
        if (StringUtils.isBlank(jsCode)) {
            return null;
        }
        String url="https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code";
        JSONObject jsonObject = new JSONObject();
        String ACCESS_TOKEN_URL = String.format(url, weChatConfig.getAppId(), weChatConfig.getAppSecret(), jsCode);
        RestTemplate restTemplate = new RestTemplate();
        String respResult = restTemplate.getForObject(ACCESS_TOKEN_URL, String.class);
        log.info("weixin pay result", respResult);
        if (Strings.isNullOrEmpty(respResult)) {
           return null;
        }
        try {
            String errorCode = JSON.parseObject(respResult).getString("errcode");
            if (errorCode != null) {
                int errorCodeInt = JSON.parseObject(respResult).getInteger("errcode");
                if (errorCodeInt != 0) {
                    return null;
                }
            }
            jsonObject = JSON.parseObject(respResult);
            return jsonObject;
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;

    }

    @Override
    public JSONObject ACCESS_TOKEN() {
        String urlToken = weChatConfig.ACCESS_TOKEN_URL.replace("APPID",weChatConfig.getAppId()).replace("SECRET",weChatConfig.getAppSecret());
        log.info("urlToken={}",urlToken);
        String tokenObj = HttpUtils.sendGet(urlToken);
        JSONObject retToken = JSONObject.parseObject(tokenObj);
        return retToken;
    }

    /**
     * 金额转换成金币
     * */
    @Override
    public Integer amountToDivide(BigDecimal amount) {
        if (amount == null || BigDecimal.ZERO.equals(amount)) {
            return 0;
        }
        BigDecimal bigDecimal = amount.setScale(2, BigDecimal.ROUND_DOWN);
        return Integer.parseInt(bigDecimal.multiply(new BigDecimal("100")).setScale(0,BigDecimal.ROUND_DOWN).toString());
    }

    @Override
    public SendSmsResponse sendSms(SmsMessageDto messageDto) {
        if (StringUtils.isBlank(messageDto.getPhoneNumbers())){
            throw new NullPointerException("未知的手机号");
        }
        //获取短信配置信息
        SmsTemplateIdEum smsConfigByName = SmsTemplateIdEum.getSmsConfigByName(messageDto.getTemplateKey());
        if(smsConfigByName==null){
            throw new NullPointerException("未知的短信类型");
        }
        // 设置超时时间-可自行根据项目设置
        System.setProperty("sun.net.client.defaultConnectTimeout", "10000");
        System.setProperty("sun.net.client.defaultReadTimeout", "10000");

        // 初始化acsClient,核心客户端,regionId:参考阿里云文档
        DefaultProfile profile = DefaultProfile.getProfile(aliyunSmsConfig.getRegionId(), aliyunSmsConfig.getAccessKeyId(), aliyunSmsConfig.getAccessKeySecret());
        IAcsClient acsClient = new DefaultAcsClient(profile);

        // 组装请求对象-具体的属性字段查看SDK文档
        SendSmsRequest request = new SendSmsRequest();
        // 必填: 待发送手机号。支持以逗号分隔的形式进行批量调用，批量上限为1000个手机号码,批量调用相对于单条调用成功率更高,且批量调用响应时间更短。
        request.setPhoneNumbers(messageDto.getPhoneNumbers());
        // 必填: 短信签名-可在短信控制台中找到
        request.setSignName(smsConfigByName.getSignName());
        // 必填: 短信模板CODE-可在短信控制台中找到
        request.setTemplateCode(smsConfigByName.getTemplateCode());
        // 必填: 短信模板变量对应的实际值，JSON格式
        request.setTemplateParam(messageDto.getTemplateParam());
        request.setSmsUpExtendCode("0");
        try {
            //SendSmsResponse response = commonService.sendSms("13888888888", "阿里云短信测试", "SMS_12345678", "{\"code\":\"123456\"}");
            // 发送短信
            SendSmsResponse response = acsClient.getAcsResponse(request);
            System.out.println("SendSmsResponse.Body:" + response.getMessage());
            return response;
        }catch (Exception e){
            e.printStackTrace();
            return null;
        }
    }


    @Override
    public String reply(Map<String, String> requestMap) {
        if(requestMap.get("content")==null){
         return "";
        }
        try {
            //扫描二维码的用户
            String userOpenid = requestMap.get("FromUserName");
            //官方
            String gongzhonghaoId = requestMap.get("ToUserName");
            WeChatMessage textMessage = WechatMessageUtils.getDefaultTextMessage(userOpenid, gongzhonghaoId);
            String content = requestMap.get("content");
            textMessage.setContent(content);
            return WechatMessageUtils.textMessageToXml(textMessage);
        }catch (Exception e){
            e.printStackTrace();
            return null;
        }
    }

    @Override
    public NotificationConfig getRSAPublicKeyNotificationConfig() {
        return new RSAAutoCertificateConfig.Builder()
                .merchantId(wxConfig.getMchID())
                .privateKeyFromPath(wxConfig.getPrivateKeyPath())
//                .publicKeyId(wxConfig.getPublicKeyId())
//                .publicKeyFromPath(wxConfig.getPublicKeyFromPath())
                .merchantSerialNumber(wxConfig.getMerchantSerialNumber())
                .apiV3Key(wxConfig.getApiV3Key())
                .build();
    }

    @Override
    public WxPrepayResp generateSignature(WxPayDto payDto){
        if (StringUtils.isBlank(payDto.getOpenId()) || payDto.getPayAmount()==0 || StringUtils.isBlank(payDto.getOutTradeNo())){
            return null;
        }
        try {
            JsapiServiceExtension service = new JsapiServiceExtension.Builder().config(getPubConfig()).build();
            // 调用预下单接口
            PrepayWithRequestPaymentResponse response = service.prepayWithRequestPayment(getPrepayRequest(payDto));
            log.info("订单【{}】发起预支付成功，返回信息：{}",payDto.getOutTradeNo(), response);
            WxPrepayResp WxPrepayResp=new WxPrepayResp()
                    .setTimeStamp(response.getTimeStamp())
                    .setNonceStr(response.getNonceStr())
                    .setPackageVal(response.getPackageVal())
                    .setSignType(response.getSignType())
                    .setPaySign(response.getPaySign());
            return WxPrepayResp;
        } catch (Exception e) { // 发送HTTP请求失败
            e.printStackTrace();
            log.error("微信下单发送HTTP请求失败，错误信息：{}", e.getMessage());
            return null;
        }
    }

    /**
     * 微信退款方法
     * @return 退款结果
     */
    @Override
    public Refund wechatRefund(WechatRefundDto dto) {
        try {
            // 使用自动更新平台证书的RSA配置
            // 建议将 config 作为单例或全局静态对象，避免重复的下载浪费系统资源
            Config config =
                    new RSAAutoCertificateConfig.Builder()
                            .merchantId(wxConfig.getMchID())
                            .privateKeyFromPath(wxConfig.getPrivateKeyPath())
                            .merchantSerialNumber(wxConfig.getMerchantSerialNumber())
                            .apiV3Key(wxConfig.getApiV3Key())
                            .build();

            // 构建退款服务
            RefundService refundService = new RefundService.Builder().config(config).build();

            // 构建退款请求
            CreateRequest request = new CreateRequest();
            request.setOutTradeNo(dto.getOutTradeNo());
            request.setOutRefundNo(dto.getOutRefundNo());
            // 添加退款回调地址
            request.setNotifyUrl("http://web.hfxxzh.cn/api/notify/wx_refund_notify");

            AmountReq amount = new AmountReq();
            amount.setRefund(dto.getRefundAmount());
            amount.setTotal(dto.getTotalAmount());
            amount.setCurrency("CNY");
            request.setAmount(amount);



            // 调用退款接口
            Refund response = refundService.create(request);
            log.info("微信退款成功，退款单号: {}", dto.getOutRefundNo());
            return response;
        } catch (Exception e) {
            log.error("微信退款失败，商户订单号: {}, 商户退款单号: {}", dto.getOutTradeNo(), dto.getOutRefundNo(), e);
            return null;
        }
    }


//    @Override
//    public CreateTransferBatchResponse transferToWechatBalance(BatchTransferDto dto) {
//        // 1. 初始化配置
//        Config config = new RSAAutoCertificateConfig.Builder()
//                .merchantId(wxConfig.getMchID())
//                .privateKeyFromPath(wxConfig.getPrivateKeyPath())
//                .merchantSerialNumber(wxConfig.getMerchantSerialNumber())
//                .apiV3Key(wxConfig.getApiV3Key())
//                .build();
//
//        // 2. 初始化转账服务
//        TransferService transferService = new TransferService.Builder()
//                .config(config)
//                .build();
//
//        // 3. 金额转换(元转分)
//        long amountInFen = dto.getAmount().multiply(new BigDecimal(100)).longValue();
//
//        // 4. 创建转账请求
//        CreateTransferBatchRequest request = new CreateTransferBatchRequest();
//        request.setAppid(wxConfig.getAppID());
//        request.setOutBatchNo(dto.getOutBatchNo());
//        request.setBatchName(dto.getBatchName() != null ? dto.getBatchName() : "商家转账");
//        request.setBatchRemark(dto.getDescription());
//        request.setTotalAmount(amountInFen);
//        request.setTotalNum(1);
//        request.setTransferDetailList(Collections.singletonList(createTransferDetail(dto, amountInFen)));
//
//        // 5. 设置回调地址(可选)
//        if (StringUtils.isNotBlank(wxConfig.getTransferNotifyUrl())) {
//            request.setNotifyUrl(wxConfig.getTransferNotifyUrl());
//        }
//
//        // 6. 发起转账
//        return transferService.createTransferBatch(request);
//    }
//
//    private TransferDetailInput createTransferDetail(BatchTransferDto dto, long amountInFen) {
//        TransferDetailInput detail = new TransferDetailInput();
//        detail.setOutDetailNo(dto.getOutBatchNo() + "01"); // 明细单号
//        detail.setTransferAmount(amountInFen);
//        detail.setTransferRemark(dto.getDescription());
//        detail.setOpenid(dto.getOpenId());
//
//        // 如需校验真实姓名
//        if (StringUtils.isNotBlank(dto.getUserName())) {
//            detail.setUserName(dto.getUserName());
//        }
//
//        return detail;
//    }
//}



    @Override
    @Transactional(rollbackFor = Exception.class)
    public void rechargeSuccess(Transaction transaction) {
        String outTradeNo = transaction.getOutTradeNo();

    }

    @Override
    public void updateBalance(SysUser user, BigDecimal income, String foreignKey, Integer target) {
        //增加余额
//        userMapper.updateBalance(user,income);
        //保存变动记录
        saveAssetRecord(user,income,foreignKey,target);
    }

    /**
     * 通过抖音小程序的 code 获取用户基本信息（openid 和 session_key）
     * @param code 抖音小程序登录时返回的 code
     * @return 包含用户基本信息的 JSONObject，如果失败则返回 null
     */
    public JSONObject getDouyinUserBasicInfoByCode(String code) {
        // 参数校验
        if (org.apache.commons.lang.StringUtils.isBlank(code)) {
            return null;
        }
        JSONObject data=new JSONObject();
        data.put("appid",douyinAppId);
        data.put("code",code);
        data.put("secret",douyinAppSecret);
        String url = "https://developer.toutiao.com/api/apps/v2/jscode2session";
//        String url = "https://developer.toutiao.com/api/douyin/getUserInfoByCode";

        try {
            String respResult = HttpUtils.sendPost(url,data.toJSONString());
            log.info("Douyin basic user info result: {}", respResult);
            if (StringUtils.isBlank(respResult)) {
                return null;
            }
            JSONObject jsonObject =JSONObject.parseObject(respResult);
            String errorCode = jsonObject.getString("err_no");
            if (errorCode == null || !"0".equals(errorCode)) {
                log.error("Failed to get Douyin basic user info, error code: {}, error msg: {}", errorCode, jsonObject.getString("description"));
                return null;
            }
            if(StringUtils.isNotBlank(jsonObject.getString("data"))){
                JSONObject res =JSONObject.parseObject(jsonObject.getString("data"));
                return res;
            }
            return null;
        } catch (Exception e) {
            e.printStackTrace();
            log.error("Error parsing Douyin basic user info response: {}", e.getMessage());
        }
        return null;
    }

    /**
     * 获取access_token
     */
    public String getDyAccessToken() {
        String url = String.format(
                "https://open.douyin.com/oauth/access_token/?client_key=%s&client_secret=%s&grant_type=client_credential",
                douyinAppId, douyinAppSecret);
        try  {
            String response=HttpUtils.sendGet(url);
            Map<String, Object> result = objectMapper.readValue(response, Map.class);
            if (result.containsKey("data")) {
                Map<String, Object> data = (Map<String, Object>) result.get("data");
                return (String) data.get("access_token");
            } else {
                throw new RuntimeException("获取access_token失败: " + result.get("message"));
            }
        } catch (Exception e) {
            throw new RuntimeException("获取access_token异常", e);
        }
    }


    /**
     * 通过抖音小程序的 code 获取用户基本信息（openid 和 session_key）
     * @param code 抖音小程序登录时返回的 code
     * @return 包含用户基本信息的 JSONObject，如果失败则返回 null
     */
//    public JSONObject getDouyinUserBasicInfoByCode(String code) {
//        try {
//            Config config = new Config().setClientKey("tt******").setClientSecret("cbs***"); // 改成自己的app_id跟secret
//            Client client = new Client(config);
//            /* 构建请求参数，该代码示例中只给出部分参数，请用户根据需要自行构建参数值
//                token:
//                   1.若用户自行维护token,将用户维护的token赋值给该参数即可
//                   2.SDK包中有获取token的函数，请根据接口path在《OpenAPI SDK 总览》文档中查找获取token函数的名字
//                     在使用过程中，请注意token互刷问题
//                header:
//                   sdk中默认填充content-type请求头，若不需要填充除content-type之外的请求头，删除该参数即可
//            */
//            V2Jscode2sessionRequest sdkRequest = new V2Jscode2sessionRequest();
//            sdkRequest.setAnonymousCode("EpFjYuaoOl");
//            sdkRequest.setAppid("tt4233**");
//            sdkRequest.setCode("YAH9JFcEc4");
//            sdkRequest.setSecret("83Soi1UKQ6");
//            V2Jscode2sessionResponse sdkResponse = client.V2Jscode2session(sdkRequest);
//        } catch (TeaException e) {
//            System.out.println(e.getMessage());
//        } catch (Exception e) {
//            System.out.println(e.getMessage());
//        }
//        return null;
//    }



    /**
     * 通过 openid 和 access_token 获取用户详细信息
     * @param openid 用户的 openid
     * @param accessToken 访问令牌
     * @return 包含用户详细信息的 JSONObject，如果失败则返回 null
     */
    public UserInfoResponse getDouyinUserDetailInfo(String openid, String accessToken) {
        String url = String.format(
                "https://open.douyin.com/oauth/userinfo/?openid=%s&access_token=%s",
                openid, getDyAccessToken());

        try{
            String response=HttpUtils.sendGet(url);
            UserInfoResponse result = objectMapper.readValue(response, UserInfoResponse.class);
            if (result.getErrcode() != null && result.getErrcode() != 0) {
                return null;
            }
            return result;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


//    /**
//     * 通过 openid 和 access_token 获取用户详细信息
//     * @param openid 用户的 openid
//     * @param accessToken 访问令牌
//     * @return 包含用户详细信息的 JSONObject，如果失败则返回 null
//     */
//    public JSONObject getDouyinUserDetailInfo(String openid, String accessToken) {
//        String url = "https://example.com/douyin/user/detail?openid=%s&access_token=%s"; // 替换为实际的抖音用户详细信息接口
//        String fullUrl = String.format(url, openid, accessToken);
//
//        RestTemplate restTemplate = new RestTemplate();
//        String respResult = restTemplate.getForObject(fullUrl, String.class);
//
//        log.info("Douyin user detail info result: {}", respResult);
//
//        if (com.google.common.base.Strings.isNullOrEmpty(respResult)) {
//            return null;
//        }
//
//        try {
//            JSONObject jsonObject = com.alibaba.fastjson.JSON.parseObject(respResult);
//            String errorCode = jsonObject.getString("error_code");
//            if (errorCode != null && !"0".equals(errorCode)) {
//                log.error("Failed to get Douyin user detail info, error code: {}, error msg: {}", errorCode, jsonObject.getString("description"));
//                return null;
//            }
//            return jsonObject;
//        } catch (Exception e) {
//            e.printStackTrace();
//            log.error("Error parsing Douyin user detail info response: {}", e.getMessage());
//        }
//        return null;
//    }



    //保存资产变动记录
    private void saveAssetRecord(SysUser user, BigDecimal income,String foreignKey,Integer type) {
        log.info("******userId********{}",user.toString());
        if(user!=null){

        }

    }

    //    @Override
    public Config getPubConfig() {
        return new RSAAutoCertificateConfig.Builder()
                .merchantId(wxConfig.getMchID())
                .privateKeyFromPath(wxConfig.getPrivateKeyPath())
//                .publicKeyId(wxConfig.getPublicKeyId())
//                .publicKeyFromPath(wxConfig.getPublicKeyFromPath())
                .merchantSerialNumber(wxConfig.getMerchantSerialNumber())
                .apiV3Key(wxConfig.getApiV3Key())
                .build();
    }

//    @Override
    public PrepayRequest getPrepayRequest(WxPayDto payDto){
        if (StringUtils.isBlank(payDto.getOpenId()) || payDto.getPayAmount()==0 || StringUtils.isBlank(payDto.getOutTradeNo())){
            return null;
        }
        PrepayRequest request = new PrepayRequest();
        Amount amount = new Amount();
        amount.setTotal(payDto.getPayAmount());
        request.setAmount(amount);
        request.setAppid(wxConfig.getAppID());
        request.setMchid(wxConfig.getMchID());
        request.setDescription(payDto.getDescription());
        request.setNotifyUrl(wxConfig.getNotifyUrl());
        request.setOutTradeNo(payDto.getOutTradeNo());
        Payer payer = new Payer();
        payer.setOpenid(payDto.getOpenId());
        request.setPayer(payer);
        return request;
    }





}





